#include <iostream>
#include <string>
#include <string.h>
#include <functional>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Common.hpp"
#include "Log.hpp"
#include "Protocol.hpp"
#include "ThreadPool.hpp"
using namespace LogModule;
using namespace ThreadPoolModule;
static const uint16_t gport = 8080;

using handler_t = std::function<std::string(std::string &)>;

class TcpServer
{
private:
    using task_t = std::function<void()>;
    struct ThreadData
    {
        int sockfd;
        TcpServer *self;
    };

public:
    TcpServer(handler_t handler, uint16_t port = gport)
        : _handler(handler), _port(port), _isrunning(false)
    {
    }
    void InitServer()
    {
        // 创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            LOG(Loglevel::FATAL) << "socket filed";
            Die(SOCKET_ERR);
        }
        LOG(Loglevel::INFO) << "socket success,sockfd:" << _listensockfd;
        // 填充网络信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        // bind绑定
        int n = bind(_listensockfd, CONV(&local), sizeof(local));
        if (n < 0)
        {
            LOG(Loglevel::FATAL) << "bind filed";
            Die(BIND_ERR);
        }
        LOG(Loglevel::INFO) << "bind success,sockfd:" << _listensockfd;
        // 将_listen设置为监听状态
        n = listen(_listensockfd, BACKLOG);
        if (n < 0)
        {
            LOG(Loglevel::FATAL) << "listen filed";
            Die(LISTEN_ERR);
        }
        LOG(Loglevel::FATAL) << "listen success,sockfd:" << _listensockfd;
    }
    static void *Entry(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = (ThreadData *)args;
        data->self->HandlerRequest(data->sockfd);
        return nullptr;
    }
    void HandlerRequest(int sockfd)
    {
        LOG(Loglevel::INFO) << "HandlerRequest,sockfd:" << sockfd;
        char inbuffer[4096];
        std::string package;
        while (true)
        {
            memset(inbuffer, 0, sizeof(inbuffer)); // 清空缓冲区
            ssize_t n = recv(sockfd, inbuffer, sizeof(inbuffer) - 1, 0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                LOG(Loglevel::INFO) << "\n"
                                    << inbuffer;
                package += inbuffer;
                std::string cmd_result = _handler(package);
                if (cmd_result.empty()) // 没有解析到完整报文,继续读取
                {
                    continue;
                }
                send(sockfd, cmd_result.c_str(), cmd_result.size(), 0); // 将处理结果发给客户端
            }
            else if (n == 0)
            {
                LOG(Loglevel::INFO) << "Client quit,sockfd:" << sockfd;
                break;
            }
            else
            {
                if (errno == EINTR)
                {
                    continue; // 信号中断,重试
                }
                LOG(Loglevel::ERROR) << "recv error" << strerror(errno);
                break;
            }
        }
        ::close(sockfd); // fd泄漏问题！
    }
    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // TCP面向连接,先建立连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensockfd, CONV(&peer), &len);
            if (sockfd < 0)
            {
                LOG(Loglevel::ERROR) << "accept filed";
            }
            LOG(Loglevel::INFO) << "accept success,sockfd:" << sockfd;

            // 进行网络传输
            // 线程池版本
            ThreadPool<task_t>::getInstance()->Equeue([this, sockfd]()
                                                      { this->HandlerRequest(sockfd); });
        }
    }
    void stop()
    {
        _isrunning = false;
    }
    ~TcpServer()
    {
    }

private:
    int _listensockfd;
    uint16_t _port;
    bool _isrunning;
    // 上层任务
    handler_t _handler;
};